# ----- coding: utf-8 -----

import re, struct, time
from crc import *


class BdHandler:
    hex_ch = ['0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F']
    have_next = False
    
    def __init__(self, conf):
        self.conf = conf
        
    
    '''
    return True active send
            False send after receive
    '''
    def handle(self, writer, req):
        have_next = False
        rsp = self.parse(req)
        if rsp:
            if isinstance(rsp, list):
                for r in rsp:
                    rsp_asc = r.encode('ascii')
                    print("response: %s\n" % (rsp_asc,))
                    writer(rsp_asc)
                    time.sleep(0.5)
            elif isinstance(rsp, str):
                rsp_asc = rsp.encode('ascii')
                print("response: %s\n" % (rsp_asc,))
                writer(rsp_asc)
            return self.have_next

    def gen_next_msg(self):
        short_msg = self.gen_short_msg(self.conf['local_id'],
                                                self.conf['remote_dev_id'], 
                                                self.conf['remote_location'],
                                                self.conf['wave_no'],
                                                self.conf['freq_no'])
        rsp = self.gen('BDTXR', '1,%s,2,,A4%s' % (self.conf['local_id'], short_msg))
        return rsp

    def parse(self, req):
        # 是否匹配$XXXXX,
        obj = re.search(r'\$([A-Z]+),', req)
        if obj:
            cmd = obj.group(1)
            print('cmd: %s\n' % (cmd,))
            # 查询卡号
            if cmd == 'CCICA':
                if self.check_req(req):
                    rsp = self.gen('BDICI', '%s,00000000,2094115,6,%d,4,N,0' % (self.conf['local_id'], self.conf['srv_interval']))
                    if self.conf['mode'] == 'passive':
                        self.have_next = True
            # 短消息    
            elif cmd == 'CCTXA':
                rsp = []
                rsp1 = self.gen('BDFKI', 'TXA,Y,Y,0,0000')
                rsp.append(rsp1)
                short_msg = self.gen_short_msg(self.conf['local_id'],
                                                self.conf['remote_dev_id'], 
                                                self.conf['remote_location'],
                                                self.conf['wave_no'],
                                                self.conf['freq_no'])
                rsp2 = self.gen('BDTXR', '1,%s,2,,A4%s' % (self.conf['local_id'], short_msg))
                rsp.append(rsp2)
            else:
                rsp = '1111111'
            return rsp
    
    def asc2hex(self, asc):
        if asc >= 'A':
            hex = 0xA + ord(asc) - ord('A')
        else:
            hex = ord(asc) - ord('0')
        return hex

    def check_req(self, req):
        start_index = req.index('$')
        end_index = req.index('*')
        #print('%s: ,@%d, *@%d' % (req, start_index, end_index))
        #if not end_index or not start_index:
        #    return False
        
        content = req[start_index+1:end_index]
        chksum_str = req[end_index+1:-2]
        print('chksum:', chksum_str)
        hi = self.asc2hex(chksum_str[0])
        lo = self.asc2hex(chksum_str[1])
        chksum = (hi << 4) | lo;
        calc_sum = self.calc_chksum(content)
        if not chksum == calc_sum:   
            print('calc_chksum: %s chksum %d' % (calc_sum, chksum))
            return False
        return True

    def calc_chksum(self, iter_info):
        # 校验和
        result = ord(iter_info[0])
        for i in range(len(iter_info)-1):
            result = result ^ ord(iter_info[i+1])
        return result    

    def gen(self, cmd, body):
        msg = '%s,%s' % (cmd, body)
        
        chksum = self.calc_chksum(msg)
        
        rsp = '$%s*%s%s\r\n' % (msg, ascii((chksum // 10)), ascii(chksum % 10))
        return rsp  

    def gen_short_msg(self, remote_id, remote_dev_id, location, wave_no, freq_no):
        byte_remote_id = bytearray(remote_id, 'ascii')
        # $BDTXR,1,2095000,2,,A4323039343030300116115994041415038000124158001010000*02
        #
        hex_msg0 = struct.pack('>BH7sBIIIBB2x', 0x81 if self.conf['mode'] == 'active' else 0x01, 24, byte_remote_id, remote_dev_id, location[0], location[1], location[2], wave_no, freq_no)
        crc = Crc.calc(hex_msg0, len(hex_msg0))
        print('crc: %s\n' % (hex(crc),))
        hex_msg = struct.pack('>27sH', hex_msg0, crc)
        #print('pack: ', hex_msg)
        list_s = []
        for i in range(len(hex_msg)):
            hi = (hex_msg[i] >> 4) & 0x0f
            lo = (hex_msg[i] & 0x0f)
            list_s.append(self.hex_ch[hi])
            list_s.append(self.hex_ch[lo])
        return ''.join(list_s)    
   
if __name__ == '__main__':
    conf = {
        'local_id': '2095000',
        'dev_id':1,
        'local_location':[380000333, 1300000111, 1200222],
        'wave_no': 0x01,
        'freq_no': 1,
        'srv_interval':30,
        'remote_id':'2094000',
        'remote_dev_id':1,
        'remote_location':[381000000, 1310000000, 1200000]}

    handler = BdHandler(conf)
    handler.handle(print, '$CCICA,0,00*7B\r\n')

    handler.handle(print, "$CCTXA,2095000,1,2,A4123456*FF\r\n")